home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume16 / fido < prev    next >
Encoding:
Internet Message Format  |  1988-11-01  |  25.5 KB

  1. Subject:  v16i053:  Watchdog for users and machines
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: budd@bu-it.bu.edu (Phil Budne)
  7. Posting-number: Volume 16, Issue 53
  8. Archive-name: fido
  9.  
  10. Fido periodically scans the files created by rwhod and reports the
  11. comings and goings of people and machines.  It reads a .fido init file to
  12. determine what to watch.  I run it as "fido &" in my console window.
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of shell archive."
  21. # Contents:  README Makefile fido.c fido.1
  22. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  23. if test -f README -a "${1}" != "-c" ; then 
  24.   echo shar: Will not over-write existing file \"README\"
  25. else
  26. echo shar: Extracting \"README\" \(331 characters\)
  27. sed "s/^X//" >README <<'END_OF_README'
  28. XFido is a program I wrote in anticipation of getting a workstation.
  29. XI keep it running in my console window.  Recently it has become popular
  30. Xwith more users, and so I've done some cleanup and sent it out.
  31. X
  32. XI don't doubt that it is a great waste of CPU, but Hey, I like it.
  33. X
  34. X        Phil Budne
  35. X        Boston University, Boston Ma
  36. X        August 1988
  37. END_OF_README
  38. if test 331 -ne `wc -c <README`; then
  39.     echo shar: \"README\" unpacked with wrong size!
  40. fi
  41. # end of overwriting check
  42. fi
  43. if test -f Makefile -a "${1}" != "-c" ; then 
  44.   echo shar: Will not over-write existing file \"Makefile\"
  45. else
  46. echo shar: Extracting \"Makefile\" \(341 characters\)
  47. sed "s/^X//" >Makefile <<'END_OF_Makefile'
  48. X# Makefile for fido.
  49. X# typing "make DEBUG=n" builds a fido of debug level n
  50. X#
  51. X# GNU's fantastic CC
  52. XCC=gcc
  53. XDFLAGS=-g
  54. XCFLAGS=-O
  55. XDEBUG=4
  56. X
  57. Xdfido$(DEBUG):    fido.c
  58. X    $(CC) $(DFLAGS) -DDEBUG=$(DEBUG) -o dfido$(DEBUG) fido.c
  59. X
  60. Xfido:    fido.c
  61. X    $(CC) $(CFLAGS) -o fido fido.c
  62. X
  63. XSHAR:    README Makefile fido.c fido.1
  64. X    shar README Makefile fido.c fido.1 > SHAR
  65. END_OF_Makefile
  66. if test 341 -ne `wc -c <Makefile`; then
  67.     echo shar: \"Makefile\" unpacked with wrong size!
  68. fi
  69. # end of overwriting check
  70. fi
  71. if test -f fido.c -a "${1}" != "-c" ; then 
  72.   echo shar: Will not over-write existing file \"fido.c\"
  73. else
  74. echo shar: Extracting \"fido.c\" \(19284 characters\)
  75. sed "s/^X//" >fido.c <<'END_OF_fido.c'
  76. X/*
  77. X *    Copyright 1988 Philip L. Budne.
  78. X *    All rights reserved.
  79. X *
  80. X *    This program may be freely distributed as long as this notice
  81. X *    and the above Copyright remain intact.
  82. X *
  83. X *    The author makes no claims of suitability for use.
  84. X */
  85. X
  86. X/*
  87. X *    Phil Budne @ BU/DSG
  88. X *
  89. X *    prehistoric    users list compiled into struct. machine
  90. X *            watching was a seperate program.
  91. X *    8/1/86        read .fido file
  92. X *    1/87        check ppid
  93. X *    8/14/87        read rwho files directly (used to popen rwho!)
  94. X *    8/20/87        add beep again, add idletime
  95. X *            rework -- put found structure in target
  96. X *            report found users once -- now way to
  97. X *            track where someone is gone from. report idle.
  98. X *    8/21/87        add machines, hungry
  99. X *    4/19/88        look in HOME for .fido, quit if not found
  100. X *            stat WHODIR, keep list of files to avoid
  101. X *            re-reading spooldir constantly!
  102. X *    8/6/88        convert to open mhash. malloc targets.
  103. X *            add stomp. remove BEEP, STOMP, MT, HOST, AT
  104. X *            use static filenamestrings.
  105. X *    8/8/88!        keep boottime and sendtime in struct machine.
  106. X *            report reboots.
  107. X *    8/9/88        All dressed up. Ready to go!
  108. X */
  109. X
  110. X/* do reverse video for machines? */
  111. X
  112. X# include <sys/types.h>
  113. X# include <sys/stat.h>
  114. X# include <sys/dir.h>
  115. X# include <strings.h>
  116. X# include <stdio.h>
  117. X# include <ctype.h>
  118. X# include <protocols/rwhod.h>        /* But not on 4.2 systems!! */
  119. X
  120. X# define EOS '\0'
  121. Xextern char *malloc();            /* from libc */
  122. X
  123. X# define bool int
  124. X# define TRUE 1
  125. X# define FALSE 0
  126. X
  127. X# define INITFILE ".fido"
  128. X
  129. X# define DEF_BEEP    FALSE
  130. X# define DEF_STAMP    TRUE
  131. X# define DEF_MACHINES    TRUE
  132. X# define DEF_DOWNTIME    8        /* minutes (less than 4 is noisy) */
  133. X# define DEF_IDLETIME    15        /* minutes */
  134. X# define DEF_SLEEPTIME    60        /* seconds */
  135. X# define MIN_SLEEPTIME    32
  136. X
  137. X# define MAXBUF 132            /* various buffers */
  138. X
  139. X/* static lengths in target struct (fields from utmp) */
  140. X# define MAXHST 33
  141. X# define MAXUSR 9
  142. X# define MAXTTY 9
  143. X
  144. X# define NUMFILES 100        /* grrr -- a hardwired limit!! */
  145. X# define BPHOST 32        /* avg length for hostnames ick!! */
  146. X
  147. Xstruct target {
  148. X    char *host, *user;
  149. X    struct found {        /* count of entries found in each state */
  150. X    int nidle, idle, hungry;
  151. X    } found[2];            /* now and before */
  152. X    struct target *tnext;
  153. X};
  154. X# define TOTAL(tp,t) ((tp)->found[t].idle + (tp)->found[t].nidle)
  155. X
  156. Xstruct target *targets;        /* list of targets */
  157. Xstruct target *lasttarget;    /* last target created */
  158. Xint numt = 0;            /* number of targets */
  159. Xint this = 0;            /* toggling index (0/1) into found array */
  160. X
  161. Xchar wildhost[] = "*";
  162. X# define WILDHOST wildhost    /* empty host for targets */
  163. X
  164. Xint beep = DEF_BEEP;
  165. Xint stamp = DEF_STAMP;
  166. Xint machines = DEF_MACHINES;
  167. Xint downtime = DEF_DOWNTIME * 60;
  168. Xint idletime = DEF_IDLETIME * 60;
  169. Xint sleeptime = DEF_SLEEPTIME;
  170. X
  171. Xchar nowstr[ 50 ];            /* for time stomping */
  172. X
  173. Xstruct machine {            /* hash table of machines */
  174. X    char name[40];
  175. X    enum { UP=1, DOWN=2 } state;
  176. X    time_t latest;            /* last time seen up */
  177. X    int boottime, sendtime;        /* from whod packet */
  178. X    struct machine
  179. X    *hnext,                /* next in hash chain */
  180. X    *anext;                /* next in list of all hosts */
  181. X};
  182. X
  183. X# define MHSIZE 101            /* small prime */
  184. Xstruct machine *mhash[ MHSIZE ], *allmachines;
  185. Xint firstpass = TRUE;
  186. X
  187. X# if DEBUG > 0
  188. Xchar *state_name[] = { "??", "UP", "DOWN" };
  189. X# endif /* DEBUG > 0 */
  190. X
  191. X# define WHODIR "/usr/spool/rwho"
  192. X
  193. X# define ISHUNGRY(we) \
  194. X    ((we->we_utmp.out_line[sizeof(we->we_utmp.out_line)-1] & 0200) != 0 )
  195. X
  196. X# define CLEARHUNGRY(we) \
  197. X    we->we_utmp.out_line[sizeof(we->we_utmp.out_line)-1] &= ~0200
  198. X
  199. Xmain() {
  200. X    int i;
  201. X
  202. X    if( !readinit( INITFILE ) ) {    /* check current dir */
  203. X    extern char *getenv();
  204. X    char tname[ 1024 ], *hp;
  205. X
  206. X    if( (hp = getenv("HOME")) == NULL ) { /* check 'home' */
  207. X        /* getpwuid(getuid()) */
  208. X        fprintf( stderr, "No ./.fido and HOME not set\n" );
  209. X        exit( 1 );
  210. X    } /* no HOME */
  211. X    sprintf( tname, "%s/%s", hp, INITFILE );
  212. X    if( !readinit( tname ) ) {
  213. X        fprintf( stderr, "No ./.fido or %s\n", tname );
  214. X        exit( 1 );
  215. X    } /* readinit failed */
  216. X    } /* no .fido in "." */
  217. X
  218. X# if DEBUG > 0
  219. X    dumpinit();
  220. X# endif /* DEBUG > 0 */
  221. X
  222. X    if( numt == 0 && !machines ) {
  223. X    fprintf(stderr, "Nothing to do!!\n" );
  224. X    exit( 1 );
  225. X    } /* nothing to do!! */
  226. X
  227. X    if( chdir( WHODIR ) < 0 ) {
  228. X    perror( WHODIR );
  229. X    exit( 1 );
  230. X    } /* chdir failed */
  231. X
  232. X    nice( 10 );                /* be nice to real users */
  233. X
  234. X    for( ; ; ) {
  235. X    dowho();            /* prowl rwho spool dir */
  236. X    if( machines )            /* watching machines? */
  237. X        scan();            /* yell about them */
  238. X    this = !this;            /* toggle found index */
  239. X    fflush( stdout );
  240. X    sleep( sleeptime );        /* go to sleep */
  241. X    if( getppid() == 1 )        /* child of init? */
  242. X        exit( 1 );            /* quitting time */
  243. X    } /* for ever */
  244. X} /* main */
  245. X
  246. Xdowho() {                /* poke thru rwho spool */
  247. X    register int i;
  248. X    register struct target *tp;
  249. X
  250. X    int now;
  251. X    char **fp;
  252. X    struct whod wd;
  253. X    struct stat newstat;
  254. X    char buf[MAXBUF], user[MAXUSR], host[MAXHST], tty[MAXTTY];
  255. X
  256. X    static int nfiles;
  257. X    static struct stat oldstat;
  258. X    static char *filenames[ NUMFILES ];    /* ACK!! hardwired limits! */
  259. X    static char filenamestrings[ NUMFILES * BPHOST ]; /* avoid malloc/free */
  260. X
  261. X    if( stat( ".", &newstat ) < 0 )
  262. X    return;
  263. X
  264. X    if( newstat.st_mtime != oldstat.st_mtime ) {
  265. X    DIR *dirp;
  266. X    struct direct *d;
  267. X    register char *dp;
  268. X
  269. X    oldstat = newstat;
  270. X# if DEBUG > 0
  271. X    puts("(re)reading RWHODIR");
  272. X# endif /* DEBUG > 0 */
  273. X
  274. X    if( (dirp = opendir( "." )) == NULL )
  275. X        return;
  276. X
  277. X    nfiles = 0;
  278. X    fp = filenames;
  279. X    dp = filenamestrings;
  280. X    while( (d = readdir( dirp )) != NULL ) {
  281. X        register char *sp;
  282. X
  283. X        if( strncmp( d->d_name, "whod.", 5 ) != 0 )
  284. X        continue;
  285. X
  286. X# if DEBUG > 4
  287. X        printf("readdir: %s\n", d->d_name );
  288. X# endif /* DEBUG > 4 */
  289. X        if( nfiles == NUMFILES ) {
  290. X        fprintf( stderr, "Too many files!! Increase NUMFILES!!\n");
  291. X        break;
  292. X        } /* too many files */
  293. X
  294. X        nfiles++;
  295. X        *fp++ = dp;
  296. X        sp = d->d_name;
  297. X        while( *dp++ = *sp++ )
  298. X        ;
  299. X    } /* while readdir */
  300. X    closedir( dirp );
  301. X    } /* rwhod mtime has changed */
  302. X
  303. X    for( tp = targets, i = 0; i < numt; tp = tp->tnext, i++ ) {
  304. X    tp->found[this].hungry = 0;
  305. X    tp->found[this].nidle  = 0;
  306. X    tp->found[this].idle   = 0;
  307. X    } /* for i */
  308. X
  309. X    time( &now );
  310. X    if( stamp ) {
  311. X    strcpy( nowstr, ctime( &now ) );
  312. X    nowstr[ 16 ] = ' ';
  313. X    nowstr[ 17 ] = EOS;        /* kill year and seconds */
  314. X    } /* stamping */
  315. X
  316. X    for( fp = filenames, i = 0; i < nfiles; i++, fp++ ) {
  317. X    register struct whoent *we;
  318. X    int f, cc, down;
  319. X    time_t recvtime;
  320. X    int try;
  321. X# ifdef USEFILETIME
  322. X    struct stat ftime;
  323. X# endif /* USEFILETIME defined */
  324. X
  325. X# if DEBUG > 19
  326. X    printf("=== %s ===\n", *fp );
  327. X# endif /* DEBUG > 19 */
  328. X
  329. X    for( try = 0; try < 5; try++, sleep(1) ) {
  330. X        cc = -1;
  331. X        if( (f = open( *fp, 0 )) < 0 )
  332. X        continue;        /* try to read again */
  333. X
  334. X        cc = read( f, &wd, sizeof( wd ));
  335. X# ifdef USEFILETIME
  336. X        fstat( f, &ftime );
  337. X# endif /* USEFILETIME defined */
  338. X        close( f );
  339. X
  340. X        cc -= sizeof( wd ) - sizeof ( wd.wd_we );
  341. X# if DEBUG > 19
  342. X        printf("%d chars\n", cc );
  343. X# endif /* DEBUG > 19 */
  344. X        if( cc < 0 ) {
  345. X# if DEBUG > 0 && DEBUG < 20
  346. X        printf("%s: %d chars\n", wd.wd_hostname, cc );
  347. X# endif /* DEBUG > 0 && DEBUG < 20 */
  348. X        continue;        /* re-read file */
  349. X        } /* short file */
  350. X        else
  351. X        break;
  352. X    } /* for each try */
  353. X    if( cc < 0 )
  354. X        continue;            /* re-read */
  355. X
  356. X# ifdef USEFILETIME
  357. X    recvtime = ftime.st_mtime;
  358. X# else  /* USEFILETIME not defined */
  359. X    recvtime = wd.wd_recvtime;
  360. X# endif /* USEFILETIME not defined */
  361. X
  362. X    down = now - recvtime;
  363. X# if DEBUG > 19
  364. X    printf( "down %d\n", down );
  365. X# endif /* DEBUG > 19 */
  366. X
  367. X    if( wd.wd_hostname[0] == EOS ) {
  368. X# if DEBUG > 0
  369. X        printf( "null hostname in file %s\n", *fp );
  370. X# endif /* DEBUG > 0 */
  371. X        continue;            /* re-read!? */
  372. X    } /* hostname empty */
  373. X
  374. X    if( machines )
  375. X        if( wd.wd_hostname[0] != EOS )
  376. X        process( &wd, recvtime );
  377. X
  378. X    if( down > downtime )        /* host is down? */
  379. X        continue;
  380. X
  381. X    for( we = wd.wd_we; cc > 0 ; we++, cc -= sizeof( *we ) ) {
  382. X        int tcnt;
  383. X        int washungry;
  384. X        register char *cp, *dp;
  385. X
  386. X        washungry = ISHUNGRY(we);    /* save hungry bit */
  387. X        CLEARHUNGRY(we);        /* clear to avoid bad comparisons */
  388. X
  389. X        strncpy( user, we->we_utmp.out_name, 8 );
  390. X        strcpy( host, wd.wd_hostname );
  391. X        strcpy( tty, we->we_utmp.out_line );
  392. X
  393. X# if DEBUG > 10
  394. X        printf("%s@%s %s idle %d\n", user, host, tty, we->we_idle );
  395. X# endif /* DEBUG > 10 */
  396. X
  397. X        for( tp = targets, tcnt = 0; tcnt < numt; tcnt++, tp = tp->tnext ) {
  398. X        if( strcmp(user, tp->user) == 0 ) { /* matching user */
  399. X            if( (dp = index( host, '.' )) != NULL )
  400. X            *dp = EOS;    /* strip domains */
  401. X
  402. X# if DEBUG > 4
  403. X# if DEBUG < 20
  404. X            printf("%s@%s %s idle %d\n",
  405. X               user, host, tty, we->we_idle );
  406. X# endif /* DEBUG < 20 */
  407. X            printf("%s %d %d\n", tp->user,
  408. X               tp->found[this].nidle,
  409. X               tp->found[this].idle );
  410. X# endif /* DEBUG > 4 */
  411. X
  412. X            if( tp->host == WILDHOST || /* wild or */
  413. X               strcmp(host, tp->host) == 0 ) { /*matching host*/
  414. X            if( we->we_idle > idletime )
  415. X                tp->found[this].idle++;
  416. X            else {        /* not idle */
  417. X                if( tp->found[this].nidle++ == 0 && /*first*/
  418. X                   tp->found[!this].nidle == 0 ) { /*none b4*/
  419. X# if DEBUG > 0 && DEBUG < 5
  420. X                tprint( tp );
  421. X# endif /* DEBUG > 0 && DEBUG < 5 */
  422. X                /* nothing before or, imbalance */
  423. X                if( tp->found[!this].idle == 0 ||
  424. X                   TOTAL(tp,this) > TOTAL(tp,!this) )
  425. X                    now_on( user, host, tty );
  426. X                else        /* return from idleness */
  427. X                    now_active( user, host, tty );
  428. X                } /* first non idle where none before */
  429. X            } /* not idle */
  430. X            if( washungry )
  431. X                if( tp->found[this].hungry++ == 0 &&
  432. X                   tp->found[!this].hungry == 0 )
  433. X                now_hungry( user, host, tty );
  434. X            } /* matching host */
  435. X            goto nextwhoent;
  436. X        } /* matching user */
  437. X        } /* for all targets */
  438. X    nextwhoent: ;
  439. X    } /* for we */
  440. X    } /* for each file */
  441. X   
  442. X    for( tp = targets, i = 0; i < numt; i++, tp = tp->tnext ) {
  443. X# if DEBUG > 49
  444. X    tprint( tp );
  445. X# endif /* DEBUG > 49 */
  446. X    if( tp->found[!this].nidle > 0 ) {     /* was here before */
  447. X# if DEBUG > 4 && DEBUG < 50
  448. X        tprint( tp );
  449. X# endif /* DEBUG > 4 && DEBUG < 50 */
  450. X        if( tp->found[this].nidle == 0 ) {    /* no non idle users */
  451. X# if DEBUG > 0 && DEBUG < 5
  452. X        tprint( tp );
  453. X# endif /* DEBUG > 0 && DEBUG < 5 */
  454. X        if( tp->found[this].idle > 0 &&    /* have idle users */
  455. X           TOTAL(tp,this) == TOTAL(tp,!this) ) /* no net change */
  456. X            now_idle( tp->user, tp->host );
  457. X        else
  458. X            now_gone( tp->user, tp->host ); /* none idle or */
  459. X                        /* net change. */
  460. X                        /* must have logged out */
  461. X        } /* no non-idle */
  462. X    } /* prev had non-idle */
  463. X    else if( tp->found[!this].idle > 0 ) {    /* prev idle? */
  464. X        if( TOTAL(tp,this) == 0 ) {        /* no current */
  465. X# if DEBUG > 0 && DEBUG < 5
  466. X        tprint( tp );
  467. X# endif /* DEBUG > 0 && DEBUG < 5 */
  468. X        now_gone( tp->user, tp->host );
  469. X        } 
  470. X    } /* here but idle before */
  471. X    } /* for tp */
  472. X} /* do who */
  473. X
  474. Xnow_on( user, host, tty )
  475. X    char *user, *host, *tty;
  476. X{
  477. X    stomp();
  478. X    printf("bow wow!! %s now on %s %s\n", user, host, tty );
  479. X} /* now on */
  480. X
  481. Xnow_active( user, host, tty )
  482. X    char *user, *host, *tty;
  483. X{
  484. X    stomp();
  485. X    printf("arf! %s active on %s %s\n", user, host, tty );
  486. X} /* now active */
  487. X
  488. Xnow_hungry( user, host, tty )
  489. X    char *user, *host, *tty;
  490. X{
  491. X    stomp();
  492. X    printf("woof! %s hungry on %s %s\n",  user, host, tty );
  493. X} /* now hungry */
  494. X
  495. Xnow_idle( user, host )
  496. X    char *user, *host;
  497. X{
  498. X    stomp();
  499. X    /* doggie noise here? */
  500. X    fputs( user, stdout );
  501. X    if( host != WILDHOST ) {
  502. X    putchar('@');
  503. X    fputs( host, stdout );
  504. X    } /* have host */
  505. X    puts(" is idle");
  506. X} /* now idle */
  507. X
  508. Xnow_gone( user, host )
  509. X    char *user, *host;
  510. X{
  511. X    stomp();
  512. X    /* doggie noise here? */
  513. X    fputs( user, stdout );
  514. X    if( host != WILDHOST ) {
  515. X    putchar('@');
  516. X    fputs( host, stdout );
  517. X    } /* have host */
  518. X    puts(" is gone");
  519. X} /* now gone */
  520. X
  521. Xnow_sated( user, host )
  522. X    char *user, *host;
  523. X{
  524. X    stomp();
  525. X    /* doggie noise here? */
  526. X    fputs( user, stdout );
  527. X    if( host != WILDHOST ) {
  528. X    putchar('@');
  529. X    fputs( host, stdout );
  530. X    } /* have host */
  531. X    puts(" is sated!!");
  532. X} /* now sated */
  533. X
  534. Xbool
  535. Xcheckflag( buf, name, ptr )
  536. X    char *name, *buf;
  537. X    bool *ptr;
  538. X{
  539. X    int l;
  540. X
  541. X    l = strlen( name );
  542. X    if( strncmp( name, buf, l ) == 0 )
  543. X    *ptr = TRUE;
  544. X    else if( buf[0] == 'n' && buf[1] == 'o' && strncmp( name, buf+2, l ) == 0 )
  545. X    *ptr = FALSE;
  546. X    else
  547. X    return( FALSE );
  548. X    return( TRUE );
  549. X} /* checkflag */
  550. X
  551. Xbool
  552. Xnumarg( buf, name, ptr, scale )
  553. X    char *name, *buf;
  554. X    int *ptr, scale;
  555. X{
  556. X    if( strncmp( name, buf, strlen( name ) ) == 0 ) {
  557. X    int i;
  558. X    if( sscanf( buf, "%*s %d", &i ) != 1 )
  559. X        fprintf( stderr, "fido: bad line: %s\n", buf );
  560. X    else
  561. X        *ptr = i * scale;
  562. X    return( TRUE );
  563. X    } /* matches */
  564. X    return( FALSE );
  565. X} /* numarg */
  566. X
  567. Xbool
  568. Xreadinit( file )
  569. X    char *file;
  570. X{
  571. X    FILE *f;
  572. X    char buf[ MAXBUF ];
  573. X
  574. X    if( (f = fopen(file, "r")) == NULL )
  575. X    return( FALSE );
  576. X
  577. X    while( fgets(buf, sizeof buf, f) != NULL ) {
  578. X    register char *cp;
  579. X
  580. X    if( (cp = index(buf,'\n')) != NULL )
  581. X        *cp = EOS;
  582. X
  583. X# if DEBUG > 9
  584. X    printf("%s\n", buf );
  585. X# endif /* DEBUG > 9 */
  586. X
  587. X    if( buf[0] == '#' )
  588. X        continue;
  589. X
  590. X    if( strncmp(buf, "user", 4) == 0 )
  591. X        r_user( buf );
  592. X    else if( checkflag(buf, "beep", &beep) )
  593. X        continue;
  594. X    else if( checkflag(buf, "machines", &machines) )
  595. X        continue;
  596. X    else if( checkflag(buf, "stamp", &stamp) )
  597. X        continue;
  598. X    else if( numarg(buf, "idletime", &idletime, 60)  )
  599. X        continue;
  600. X    else if( numarg(buf, "downtime", &downtime, 60)  )
  601. X        continue;
  602. X    else if( numarg(buf, "sleeptime", &sleeptime, 1) )
  603. X        continue;
  604. X    else
  605. X        fprintf(stderr, "fido: bad line in %s: %s\n", file, buf );
  606. X    } /* while */
  607. X    if( sleeptime < MIN_SLEEPTIME )
  608. X    sleeptime = MIN_SLEEPTIME;
  609. X    fclose ( f );
  610. X    return( TRUE );
  611. X} /* readinit */
  612. X
  613. Xchar *savestr( s )
  614. Xregister char *s;
  615. X{
  616. X    register char *t;
  617. X
  618. X    while( *s != EOS && isspace( *s ) )
  619. X    s++;
  620. X    if( *s == EOS )
  621. X    return( "" );
  622. X
  623. X    t = s;
  624. X    while( *t != EOS && !isspace( *t ) && *t != '\n' )
  625. X    t++;
  626. X    if( *t != EOS )
  627. X    *t = EOS;
  628. X
  629. X# if DEBUG > 10
  630. X    printf("savestr '%s'\n", s);
  631. X# endif /* DEBUG > 10 */
  632. X
  633. X    return( strcpy( malloc( strlen( s ) + 1 ), s) );
  634. X    
  635. X} /* savestr */
  636. X
  637. Xr_user( l )
  638. Xregister char *l;
  639. X{
  640. X    register char *cp;
  641. X    register struct target *tp;
  642. X
  643. X    while( *l != EOS && !isspace( *l ) )
  644. X      l++;
  645. X
  646. X    while( *l != EOS && isspace( *l ) )
  647. X      l++;
  648. X
  649. X    if( *l == EOS )
  650. X    return;
  651. X
  652. X    tp = (struct target *) malloc( sizeof( struct target ) );
  653. X    tp->tnext = NULL;
  654. X
  655. X    if( targets == NULL )
  656. X    targets = tp;
  657. X    else
  658. X    lasttarget->tnext = tp;
  659. X
  660. X    if( (cp = index(l, '@')) != NULL ) {
  661. X    *cp++ = EOS;            /* blast @ to tie off user */
  662. X    if( *cp != EOS )        /* have host? */
  663. X        tp->host = savestr( cp );    /* save it */
  664. X    else                /* none? */
  665. X        tp->host = WILDHOST;    /* WTF -- save as wild */
  666. X    } /* have host */
  667. X    else
  668. X    tp->host = WILDHOST;
  669. X    tp->user = savestr( l );
  670. X
  671. X    tp->found[0].idle   = 0;
  672. X    tp->found[0].nidle  = 0;
  673. X    tp->found[0].hungry = 0;
  674. X    tp->found[1].idle   = 0;
  675. X    tp->found[1].nidle  = 0;
  676. X    tp->found[1].hungry = 0;
  677. X
  678. X    lasttarget = tp;
  679. X    numt++;
  680. X} /* r_user */
  681. X
  682. Xdumpinit() {
  683. X    register int i;
  684. X    register struct target *tp;
  685. X
  686. X    for( tp = targets, i = 0; i < numt; tp = tp->tnext, i++ )
  687. X    if( tp->host == WILDHOST )
  688. X        printf("%s\n", tp->user );
  689. X    else
  690. X        printf("%s@%s\n", tp->user, tp->host );
  691. X} /* dumpinit */
  692. X
  693. X/**************** machine stuff ****************/
  694. X
  695. X# define SH 7
  696. X# define WS 32
  697. Xunsigned
  698. Xhash( n )
  699. X    register char *n;
  700. X{
  701. X    register unsigned l, i;
  702. X
  703. X    i = l = 0;
  704. X    while( *n != EOS ) {
  705. X    i = ((i << SH) | (i >> (WS-SH))) ^ *n++;
  706. X    l++;
  707. X    } /* while not end of string */
  708. X    return( (i + l) % MHSIZE );
  709. X} /* hash */
  710. X
  711. Xstruct machine *
  712. Xfindmachine( n )
  713. X    char *n;
  714. X{
  715. X    int h;
  716. X    register struct machine *mp;
  717. X
  718. X    h = hash( n );
  719. X    for( mp = mhash[ h ]; mp != NULL; mp = mp->hnext )
  720. X    if( strcmp(mp->name, n) == 0 )
  721. X        return( mp );
  722. X    return( NULL );
  723. X} /* findmachine */
  724. X
  725. Xstruct machine *
  726. Xnewmachine( n )
  727. X    char *n;
  728. X{
  729. X    int h;
  730. X    register struct machine *mp;
  731. X
  732. X    mp = (struct machine *) malloc( sizeof( struct machine ) );
  733. X    strcpy(mp->name, n);
  734. X    mp->state = UP;
  735. X
  736. X    mp->anext = allmachines;        /* put in list of all machines */
  737. X    allmachines = mp;
  738. X
  739. X    h = hash( n );            /* put in hash list */
  740. X    mp->hnext = mhash[ h ];
  741. X    mhash[ h ] = mp;
  742. X
  743. X    if( !firstpass )
  744. X    saynew( mp );
  745. X
  746. X    return( mp );
  747. X} /* newmachine */
  748. X
  749. Xprocess( wd, t )
  750. X    struct whod *wd;
  751. X    time_t t;
  752. X{
  753. X    struct machine *mp;
  754. X
  755. X    if( (mp = findmachine( wd->wd_hostname )) != NULL ) {
  756. X# if DEBUG > 10
  757. X    printf("found machine: %s\n", wd->wd_hostname);
  758. X# endif /* DEBUG > 10 */
  759. X    if( wd->wd_boottime - mp->boottime > 120 ) { /* filter out freaks */
  760. X        sayreboot( mp );
  761. X# if DEBUG > 0        
  762. X        printf("new %d old %d diff %d\n",
  763. X           wd->wd_boottime,
  764. X           mp->boottime,
  765. X           wd->wd_boottime - mp->boottime );
  766. X# endif /* DEBUG > 0 */
  767. X    } /* new boottime */
  768. X    } /* machine found */
  769. X    else
  770. X    mp = newmachine( wd->wd_hostname );
  771. X
  772. X    mp->latest = t;            /* packet sendtime or file time */
  773. X    mp->boottime = wd->wd_boottime;
  774. X    mp->sendtime = wd->wd_sendtime;
  775. X} /* process */
  776. X
  777. Xscan() {
  778. X    register struct machine *mp;
  779. X    int i;
  780. X    time_t now;
  781. X
  782. X    time( &now );
  783. X    for( mp = allmachines; mp != NULL; mp = mp->anext ) {
  784. X# if DEBUG > 4
  785. X    printf("scan: %s (%s)\n", mp->name, state_name[ mp->state+1 ] );
  786. X# endif /* DEBUG > 4 */
  787. X    /*
  788. X     * if /usr/spool/rwho is on another machine (via NFS) and our
  789. X     * clocks differ we get alot of up/down noise.  there must be
  790. X     * a good way to dampen this!!
  791. X     *
  792. X     * perhaps keep a new state "may be down" as a cushion
  793. X     *
  794. X     * perhaps keep threshold per host and increase each time the
  795. X     * host comes "up" without having been rebooted (see
  796. X     * wd_boottime)
  797. X     */
  798. X    if( now - mp->latest > downtime ) { /* now down */
  799. X        if( mp->state != DOWN ) {
  800. X        saydown( mp, now - mp->latest );
  801. X        mp->state = DOWN;
  802. X        } /* new state: down */
  803. X    } /* now down */
  804. X    else {            /* now up */
  805. X        if( mp->state != UP ) {
  806. X        sayup( mp );
  807. X        mp->state = UP;
  808. X        } /* new state: up */
  809. X    } /* now up */
  810. X    } /* for all machines */
  811. X    firstpass = FALSE;
  812. X} /* scan */
  813. X
  814. Xstomp() {
  815. X    if( beep )
  816. X    putchar('\007');
  817. X    if( stamp )
  818. X    fputs( nowstr, stdout );
  819. X} /* stomp */
  820. X
  821. Xsaydown( mp, t )
  822. X    struct machine *mp;
  823. X    int t;
  824. X{
  825. X    int d, h, m;
  826. X
  827. X    stomp();
  828. X    printf("%s is down (", mp->name );
  829. X    t /= 60;                /* toss seconds */
  830. X    m = t % 60;                /* get mins */
  831. X    t /= 60;                /* toss mins */
  832. X    d = t % 24;                /* get days */
  833. X    t /= 24;                /* cast out days */
  834. X    t %= 7;                /* get weeks!! */
  835. X    if( t > 0 ) printf("%dw", t );
  836. X    if( d > 0 ) printf("%dd", d );
  837. X    if( h > 0 ) printf("%dh", h );
  838. X    if( m > 0 ) printf("%dm", m );
  839. X    puts(")");
  840. X} /* saydown */
  841. X
  842. Xsayup( mp )
  843. X    struct machine *mp;
  844. X{
  845. X    stomp();
  846. X    printf("%s is up\n", mp->name );
  847. X} /* sayup */
  848. X
  849. Xsaynew( mp )
  850. X    struct machine *mp;
  851. X{
  852. X    stomp();
  853. X    printf("new machine: %s\n", mp->name );
  854. X} /* saynew sayme */
  855. X
  856. Xsayreboot( mp )
  857. X    struct machine *mp;
  858. X{
  859. X    stomp();
  860. X    printf("%s rebooted\n", mp->name );
  861. X} /* saynew sayme */
  862. X
  863. X# if DEBUG > 0
  864. Xtprint( tp )
  865. X    register struct target *tp;
  866. X{
  867. X    printf("%s (%d %d %d) (%d %d %d)",
  868. X       tp->user,
  869. X
  870. X       tp->found[this].nidle,
  871. X       tp->found[this].idle,
  872. X       tp->found[this].hungry,
  873. X
  874. X       tp->found[!this].nidle,
  875. X       tp->found[!this].idle,
  876. X       tp->found[!this].hungry
  877. X       );
  878. X    if( TOTAL(tp,this) != TOTAL(tp,!this) )
  879. X    printf(" ***** net imbalance!! *****");
  880. X    puts("");
  881. X} /* tprint */
  882. X# endif /* DEBUG > 0 */
  883. END_OF_fido.c
  884. if test 19284 -ne `wc -c <fido.c`; then
  885.     echo shar: \"fido.c\" unpacked with wrong size!
  886. fi
  887. # end of overwriting check
  888. fi
  889. if test -f fido.1 -a "${1}" != "-c" ; then 
  890.   echo shar: Will not over-write existing file \"fido.1\"
  891. else
  892. echo shar: Extracting \"fido.1\" \(2894 characters\)
  893. sed "s/^X//" >fido.1 <<'END_OF_fido.1'
  894. X.\"-*-nroff-*-
  895. X.TH FIDO 1 "9 Aug 1988"
  896. X.SH NAME
  897. Xfido \- a watchdog for users and machines
  898. X.SH SYNOPSIS
  899. X.B fido &
  900. X.SH FEATURES
  901. X.I Fido
  902. Xperiodically scans the files created by
  903. X.IR rwhod (8c)
  904. Xand reports the commings and goings of people and machines.
  905. X.I Fido
  906. Xreads a
  907. X.I .fido
  908. Xinit file to determine what to watch. 
  909. X.I .fido
  910. Xis first checked for in the current directory, and then
  911. Xin the directory contained in the
  912. X.B \s-1HOME\s0
  913. Xenvironment variable.
  914. X.PP
  915. XThe
  916. X.I .fido
  917. Xfile consists of a list of commands from the list below.
  918. XLines starting with a hash-mark (#) are discarded as comments.
  919. X.HP
  920. X.B user
  921. X.IR user [@ host ]
  922. X.br
  923. XWatch for a specified user.  Normally only the first login and last
  924. Xlogout of the specified user will be reported.  If a host is
  925. Xspecified, then only instances of that user on that host are reported
  926. X(useful when multiple users have the same name).  You can have
  927. Xmultiple lines with the same username and different hosts (including
  928. Xthe form with no host).
  929. X.HP
  930. X.RB [ no ] beep
  931. X.br
  932. XRing bell on output (default is
  933. X.BR nobeep )
  934. X.HP
  935. X.RB [ no ] machines
  936. X.br
  937. XWatch machines go up and down (default is
  938. X.BR machines )
  939. X.HP
  940. X.RB [ no ] stamp
  941. X.br
  942. XOutput timestamps. (default is
  943. X.BR stamp )
  944. X.HP
  945. X.B idletime
  946. X.I minutes
  947. X.br
  948. XSpecify the 
  949. Xnumber of minutes until a user is declared idle (default is 15).
  950. X.HP
  951. X.B downtime
  952. X.I minutes
  953. X.br
  954. XSpecify the number of minutes before a host is declared down (default is 8).
  955. X.B Note!!
  956. XIf the
  957. X.IR rwho (1c)
  958. Xspool directory is located on another (NFS) host, a skew between
  959. Xtime of day clocks can cause major misery.
  960. X.HP
  961. X.B sleeptime
  962. X.I seconds
  963. X.br
  964. XSpecify number of seconds to sleep between scans (default is 60,
  965. Xminimum is 32).
  966. X.PP
  967. XYou must specify at least one
  968. X.B user
  969. Xline or
  970. X.B machines
  971. Xin your
  972. X.I .fido
  973. Xfile, otherwise
  974. X.I fido
  975. Xhas nothing to to!!
  976. XEach time it wakes up
  977. X.I fido
  978. Xchecks to see if it's parent pid is now pid 1 (init), if this
  979. Xis true, then
  980. X.IR fido 's
  981. Xorginal parent must have exited, and so
  982. X.I fido
  983. Xfollows its master into oblivion.
  984. X.SH FILES
  985. X.TP 20
  986. X.I /usr/spool/rwho
  987. Xrwho spool area
  988. X.PD 0
  989. X.TP
  990. X.I ./.fido
  991. Xfido init file first choice
  992. X.TP
  993. X.RI $\s-1HOME\s0 /.fido
  994. Xfido init file
  995. X.PD
  996. X.SH SEE ALSO
  997. X.IR who (1),
  998. X.IR rwho (1c),
  999. X.IR ruptime (1c),
  1000. X.IR environ (5v),
  1001. X.IR rwhod (8c),
  1002. X.IR hungry (l)
  1003. X.SH AUTHOR
  1004. XPhilip L. Budne, Boston University, Distributed Systems Group
  1005. X.SH BUGS
  1006. XSee features.
  1007. X.PP
  1008. XNo way to exclude a given machine, or user on a given machine.
  1009. X.PP
  1010. XNo way to specify a particular terminal line.
  1011. X.PP
  1012. XNo way to specify any user on a given host (ie; watch for idle
  1013. Xworkstations)
  1014. X.PP
  1015. X.I Fido
  1016. Xwas inspired by a program of the same name running on the MIT
  1017. XITS operating system for PDP-10s.
  1018. X.PP
  1019. X.I Fido
  1020. Xcan only read 100 files from
  1021. X.I /usr/spool/rwho
  1022. X(see
  1023. X.B \s-1NUMFILES\s0
  1024. Xin the source)
  1025. Xand the total number of bytes consumed by the filenames
  1026. Xcannot exceed
  1027. X.BR \s-1BPHOST\s0 "*" \s-1NUMFILES\s0 .
  1028. X.RB ( \s-1BPHOST\s0
  1029. Xis currently 32)
  1030. END_OF_fido.1
  1031. if test 2894 -ne `wc -c <fido.1`; then
  1032.     echo shar: \"fido.1\" unpacked with wrong size!
  1033. fi
  1034. # end of overwriting check
  1035. fi
  1036. echo shar: End of shell archive.
  1037. exit 0
  1038.  
  1039.